﻿
Imports System.Threading
Imports std

Namespace storageJobConsumerInternal
    Partial Public MustInherit Class diskslice(Of ATOM_T As atom)
        Private Function opened_wrappered(ByVal c As _do(Of eventComb)) As eventComb
            assert(Not c Is Nothing)
            Dim ec As eventComb = Nothing
            Return New eventComb(Function() As Boolean
                                     If Not opened() Then
                                         Return False
                                     Else
                                         ec = c()
                                         Return waitfor(ec) AndAlso
                                                goto_next()
                                     End If
                                 End Function,
                                 Function() As Boolean
                                     Return ec.end_result() AndAlso
                                            goto_end()
                                 End Function)
        End Function

        Private Function diskoper_wrappered(ByVal c As _do(Of eventComb),
                                            Optional ByVal d As _do(Of Boolean) = Nothing) As eventComb
            assert(Not c Is Nothing)
            Dim diskoper As diskoper = Nothing
            diskoper = start_diskoper()
            Return chain_after(Function() As eventComb
                                   Return c()
                               End Function,
                               Function() As Boolean
                                   end_diskoper(diskoper)
                                   Return True
                               End Function,
                               Function() As Boolean
                                   Return do_(d, True)
                               End Function,
                               accept_null_ec:=True)
        End Function

        Private Function diskoper_wrappered(ByVal c As _do(Of eventComb),
                                            ByVal result As pointer(Of Boolean)) As eventComb
            Return diskoper_wrappered(c,
                                      Function() As Boolean
                                          Return eva(result, True)
                                      End Function)
        End Function

        Public Function capacity(ByVal result As pointer(Of Int64)) As eventComb Implements iasyncslice.capacity
            Return sync_to_async_wrapper.sync_to_async(result,
                                                       Function(ByRef r) _
                                                           eva(r, driveFreeSpace() \ shareDriveDisksliceCount()))
        End Function

        Private Function delete_existing(ByVal it As map(Of String, ATOM_T).iterator,
                                         ByVal atom As ATOM_T,
                                         ByVal result As pointer(Of Boolean)) As eventComb
            Return opened_wrappered(
                        Function() As eventComb
                            assert(Not it Is Nothing)
                            assert(it <> index.end())
                            assert(Not atom Is Nothing)
                            Dim moveec As eventComb = Nothing
                            Dim moveresult As pointer(Of Int64) = Nothing
                            Dim diskoper As diskoper = Nothing
                            Return chain(as_predict(Function() As Boolean
                                                        index.erase(it)
                                                        moveresult = New pointer(Of Int64)()
                                                        diskoper = start_diskoper()
                                                        Return streammove4(stream(),
                                                                           atom.end(),
                                                                           atom.start(),
                                                                           ec:=moveec,
                                                                           result:=moveresult)
                                                    End Function),
                                         as_eventComb(Function() As eventComb
                                                          Return moveec
                                                      End Function,
                                                      True),
                                         as_eventComb(Function() As eventComb
                                                          assert(+moveresult = stream.Length() - atom.end())
                                                          stream().SetLength(stream().Length() - atom.length())
                                                          Return delete(atom)
                                                      End Function,
                                                      True),
                                         as_predict(Function() As Boolean
                                                        end_diskoper(diskoper)
                                                        Return traversal_index(
                                                                      Function(ByRef s As String,
                                                                               ByRef a As ATOM_T) As Boolean
                                                                                      If a.start() > atom.start() Then
                                                                                          a.backward(atom.length())
                                                                                      End If
                                                                                      Return True
                                                                                  End Function) AndAlso
                                                               eva(result, True)
                                                    End Function))
                        End Function)
        End Function

        Public Function delete(ByVal key As String,
                               ByVal result As pointer(Of Boolean)) As eventComb Implements iasyncslice.delete
            Dim it As map(Of String, ATOM_T).iterator = Nothing
            Dim atom As ATOM_T = Nothing
            If find_index(key, it, atom) Then
                Return delete_existing(it, atom, result)
            Else
                Return sync_to_async_wrapper.sync_to_async(result, Function(ByRef r) eva(r, False))
            End If
        End Function

        Public Function empty(ByVal result As pointer(Of Boolean)) As eventComb Implements iasyncslice.empty
            Return sync_to_async_wrapper.sync_to_async(result, Function(ByRef r) eva(r, index.empty()))
        End Function

        Public Function full(ByVal result As pointer(Of Boolean)) As eventComb Implements iasyncslice.full
            Return opened_wrappered(
                        Function() sync_to_async_wrapper.sync_to_async(result,
                                                                       Function(ByRef r) _
                                                                       eva(r, index.size() >= maxAtomsCount() OrElse
                                                                              stream().Length() >= maxIndexSize() OrElse
                                                                              driveFreeSpace() <= 0)))
        End Function

        Public Function heartbeat(ByVal result As pointer(Of Boolean)) As eventComb Implements iasyncslice.heartbeat
            Dim wakeup As void = Nothing
            Dim start As _do(Of Boolean) =
                Function() As Boolean
                    managedThreadPool.global.insertJob(Sub()
                                                           eva(result, (Not opened() OrElse close()) AndAlso open())
                                                           assert(Not wakeup Is Nothing)
                                                           wakeup()
                                                       End Sub,
                                                       Nothing)
                    Return True
                End Function
            Return New eventComb(Function() As Boolean
                                     Return waitfor(wakeup) AndAlso
                                            start() AndAlso
                                            goto_end()
                                 End Function)
        End Function

        Public Function keycount(ByVal result As pointer(Of Int64)) As eventComb Implements iasyncslice.keycount
            Return sync_to_async_wrapper.sync_to_async(result, Function(ByRef r) eva(r, index.size()))
        End Function

        Public Function list(ByVal result As pointer(Of vector(Of String))) As eventComb Implements iasyncslice.list
            Return sync_to_async_wrapper.sync_to_async(result,
                                                       Function(ByRef r As vector(Of String)) As Boolean
                                                           Dim v As vector(Of String) = Nothing
                                                           v = New vector(Of String)()
                                                           Return traversal_index(Function(ByRef key As String,
                                                                                           ByRef atom As ATOM_T) _
                                                                                          As Boolean
                                                                                      Return v.push_back(key)
                                                                                  End Function) AndAlso
                                                                  eva(r, v)
                                                       End Function)
        End Function

        Public Function modify(ByVal key As String,
                               ByVal buff As bytes,
                               ByVal result As pointer(Of Boolean)) As eventComb Implements iasyncslice.modify
            Dim it As map(Of String, ATOM_T).iterator = Nothing
            Dim atom As ATOM_T = Nothing
            If find_index(key, it, atom) Then
                If modifiable Then
                    Return diskoper_wrappered(Function() As eventComb
                                                  Return modify(atom, buff)
                                              End Function,
                                              result)
                Else
                    Dim deleteresult As pointer(Of Boolean) = Nothing
                    Dim writeresult As pointer(Of Boolean) = Nothing
                    Return chain(as_eventComb(Function() As eventComb
                                                  deleteresult = New pointer(Of Boolean)()
                                                  Return delete_existing(it, atom, deleteresult)
                                              End Function),
                                 as_predict(Function() As Boolean
                                                Return +deleteresult
                                            End Function),
                                 as_eventComb(Function() As eventComb
                                                  writeresult = New pointer(Of Boolean)()
                                                  Return write_non_existing(key, buff, writeresult)
                                              End Function),
                                 as_predict(Function() As Boolean
                                                Return +writeresult AndAlso eva(result, True)
                                            End Function))
                End If
            Else
                Return write_non_existing(key, buff, result)
            End If
        End Function

        Private Function read_existing(ByVal atom As ATOM_T, ByVal result As pointer(Of bytes)) As eventComb
            Return diskoper_wrappered(Function() As eventComb
                                          Return read(atom, result)
                                      End Function)
        End Function

        Public Function read(ByVal key As String,
                             ByVal result As pointer(Of bytes)) As eventComb Implements iasyncslice.read
            Dim atom As ATOM_T = Nothing
            If find_index(key, atom) Then
                Return read_existing(atom, result)
            Else
                Return sync_to_async_wrapper.sync_to_async(result,
                                                           Function(ByRef r As bytes) As Boolean
                                                               Return eva(r, [default](Of bytes)())
                                                           End Function)
            End If
        End Function

        Public Function retire(ByVal result As pointer(Of Boolean)) As eventComb Implements iasyncslice.retire
            Return sync_to_async_wrapper.sync_to_async(result,
                                                       Function(ByRef r) _
                                                           eva(r, close() And retire() And create_open()))
        End Function

        Public Function seek(ByVal key As String,
                             ByVal result As pointer(Of Boolean)) As eventComb Implements iasyncslice.seek
            Return sync_to_async_wrapper.sync_to_async(result,
                                                       Function(ByRef r) eva(r, find_index(key, Nothing)))
        End Function

        Public Function sizeof(ByVal key As String,
                               ByVal result As pointer(Of Int64)) As eventComb Implements iasyncslice.sizeof
            Return sync_to_async_wrapper.sync_to_async(result,
                                                       Function(ByRef r As Int64) As Boolean
                                                           Dim atom As ATOM_T = Nothing
                                                           If find_index(key, atom) Then
                                                               eva(r, sizeof(atom))
                                                           Else
                                                               eva(r, npos)
                                                           End If
                                                           Return True
                                                       End Function)
        End Function

        Public Function valuesize(ByVal result As pointer(Of Int64)) As eventComb Implements iasyncslice.valuesize
            Return sync_to_async_wrapper.sync_to_async(result,
                                                       Function(ByRef r As Int64) As Boolean
                                                           Dim total As Int64 = 0
                                                           If Not index.empty() Then
                                                               assert(traversal_index(
                                                                          Function(ByRef key As String,
                                                                                   ByRef atom As ATOM_T) _
                                                                                  As Boolean
                                                                              Dim this As Int64 = 0
                                                                              this = sizeof(atom)
                                                                              If this = npos Then
                                                                                  total = npos
                                                                                  Return False
                                                                              Else
                                                                                  total += this
                                                                                  Return True
                                                                              End If
                                                                          End Function) =
                                                                      (total <> npos))
                                                           End If
                                                           Return eva(r, total)
                                                       End Function)
        End Function

        Protected Function write_meta(ByVal meta As bytes,
                                      ByVal atom As ATOM_T) As eventComb
            Dim ec As eventComb = Nothing
            Return opened_wrappered(Function() As eventComb
                                        Return _
                       chain(as_predict(Function() As Boolean
                                            stream().Position() = atom.metaStart()
                                            Return writestream4(stream(),
                                                                +meta,
                                                                meta.size(),
                                                                holdtime:=diskslice.diskOperDefaultHoldtimeMs,
                                                                ec:=ec)
                                        End Function),
                             as_eventComb(Function() As eventComb
                                              Return ec
                                          End Function,
                             True))
                                    End Function)
        End Function

        Private Function write_non_existing(ByVal key As String,
                                            ByVal buff As bytes,
                                            ByVal result As pointer(Of Boolean)) As eventComb
            Dim atom As ATOM_T = Nothing
            Return opened_wrappered(Function() As eventComb
                                        Return _
                   diskoper_wrappered(Function() As eventComb
                                          Dim metaLength As UInt64 = 0
                                          metaLength = Me.metaLength(buff)
                                          assert(stream().Seek(0, IO.SeekOrigin.End) = stream().Length())
                                          Dim start As UInt64 = 0
                                          start = stream().Position()
                                          writer().Write(key)
                                          writer().Write(metaLength)
                                          writer().Write(checksum_64)
                                          atom = atom_ctor(start, stream().Position(), metaLength)
                                          index(key) = atom
                                          Dim meta As bytes = Nothing
                                          meta = Me.meta(atom, buff)
                                          Return chain(as_eventComb(Function() As eventComb
                                                                        If meta Is Nothing Then
                                                                            Return Nothing
                                                                        Else
                                                                            Return write_meta(meta, atom)
                                                                        End If
                                                                    End Function,
                                                                    True),
                                                       as_eventComb(Function() As eventComb
                                                                        Return write(atom, buff)
                                                                    End Function,
                                                                    True),
                                                       as_predict(Function() As Boolean
                                                                      Return eva(result, True)
                                                                  End Function))
                                      End Function)
                                    End Function)
        End Function

        Public Function write(ByVal key As String,
                              ByVal buff As bytes,
                              ByVal result As pointer(Of Boolean)) As eventComb Implements iasyncslice.write
            Dim it As map(Of String, ATOM_T).iterator = Nothing
            Dim atom As ATOM_T = Nothing
            If find_index(key, it, atom) Then
                If modifiable Then
                    Return diskoper_wrappered(Function() As eventComb
                                                  Return append(atom, buff)
                                              End Function,
                                              result)
                Else
                    Dim writeresult As pointer(Of Boolean) = Nothing
                    Dim originalbuff As pointer(Of bytes) = Nothing
                    Dim deleteresult As pointer(Of Boolean) = Nothing
                    Dim mergedbuff As bytes = Nothing
                    Return chain(as_eventComb(Function() As eventComb
                                                  originalbuff = New pointer(Of bytes)()
                                                  Return read_existing(atom, originalbuff)
                                              End Function),
                                 as_predict(Function() As Boolean
                                                Return Not +originalbuff Is Nothing
                                            End Function),
                                 as_eventComb(Function() As eventComb
                                                  deleteresult = New pointer(Of Boolean)()
                                                  Return delete_existing(it, atom, deleteresult)
                                              End Function),
                                 as_eventComb(Function() As eventComb
                                                  mergedbuff = New bytes(+originalbuff)
                                                  mergedbuff += buff
                                                  writeresult = New pointer(Of Boolean)()
                                                  Return write_non_existing(key, mergedbuff, writeresult)
                                              End Function),
                                 as_predict(Function() As Boolean
                                                Return +writeresult AndAlso eva(result, True)
                                            End Function))
                End If
            Else
                Return write_non_existing(key, buff, result)
            End If
        End Function

        Public Sub [stop]() Implements iasyncslice.stop
            If opened() Then
                close()
            End If
        End Sub
    End Class
End Namespace
